set(AVALAIBLE_SANITIZERS "address;leak;memory;thread;undefined")
set(USE_SANITIZER "" CACHE STRING "Enable sanitizer(s). Options are: ${AVALAIBLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible.")
string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER)

if((CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo") AND USE_SANITIZER)
    message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types.")
endif()

if(USE_SANITIZER)
    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
        set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")

        if(USE_SANITIZER MATCHES "address")
            list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION)
        else()
            message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.")
        endif()
    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
        if(USE_SANITIZER MATCHES "address")
            list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION)
            list(APPEND SANITIZER_LINK_LIBRARIES clang_rt.asan_dynamic-x86_64 clang_rt.asan_dynamic_runtime_thunk-x86_64)
        else()
            message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.")
        endif()
    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        foreach(sanitizer ${USE_SANITIZER})
            if(NOT ${sanitizer} IN_LIST AVALAIBLE_SANITIZERS)
                message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVALAIBLE_SANITIZERS}.")
            endif()
            list(APPEND SANITIZER_COMPILE_OPTIONS -fsanitize=${sanitizer})
            list(APPEND SANITIZER_LINK_OPTIONS -fsanitize=${sanitizer})
            if (${sanitizer} MATCHES "memory")
                list(APPEND SANITIZER_LINK_LIBRARIES -fsanitize-memory-track-origins -fPIE -pie)
                list(APPEND SANITIZER_LINK_OPTIONS -fsanitize-memory-track-origins -fPIE -pie)
            endif()
        endforeach()
        list(APPEND SANITIZER_COMPILE_OPTIONS -fno-omit-frame-pointer)
    else()
        message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}")
    endif()

    list(REMOVE_DUPLICATES SANITIZER_COMPILE_OPTIONS)
    list(REMOVE_DUPLICATES SANITIZER_LINK_OPTIONS)
    list(REMOVE_DUPLICATES SANITIZER_LINK_LIBRARIES)

    message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}")
endif()